Minimal Abbreviation

Time: O(2^N); Space: O(N); hard

A string such as “word” contains the following abbreviations: [“word”, “1ord”, “w1rd”, “wo1d”, “wor1”, “2rd”, “w2d”, “wo2”, “1o1d”, “1or1”, “w1r1”, “1o2”, “2r1”, “3d”, “w3”, “4”]

Given a target string and a set of strings in a dictionary, find an abbreviation of this target string with thesmallest possible length such that it does not conflict with abbreviations of the strings in the dictionary.

Each number or letter in the abbreviation is considered length = 1.

For example, the abbreviation “a32bc” has length = 4.

Notes:

  • In the case of multiple answers as shown in the second example below, you may return any one of them.

  • Assume length of target string = M, and dictionary size = N.

  • You may assume that M <= 21, N <= 1000, and log2(N) + M <= 20.

Example 1:

Input: “apple”, [“blade”]

Output: “a4”

Explanation:

  • “5” or “4e” conflicts with “blade”

Example 2:

Input: “apple”, [“plain”, “amber”, “blade”]

Output: “1p3”

Explanation:

  • Other valid answers include “ap3”, “a3e”, “2p2”, “3le”, “3l1”.

This is a combination of Valid Word Abbreviation and Generalized Abbreviation.

We first find all abbreviations for the target word, then check with each word in the dict to see if it conflicts with any one of them (by checking if the abbreviation is a valid one for the word in the dict).

Since we need to find the abbreviation with the minimum length, we use a priority queue which is ordered by length.

Thus the first valid abbreviation is the one we want.

[1]:
class Solution1object):
    def minAbbreviation(self, target, dictionary) -> str:
        """
        :type target: str
        :type dictionary: List[str]
        :rtype: str
        """
        def bits_len(target, bits):
            return sum(((bits >> i) & 3) == 0 for i in range(len(target)-1))

        diffs = []
        for word in dictionary:
            if len(word) != len(target):
                continue
            diffs.append(sum(2**i for i, c in enumerate(word) if target[i] != c))

        if not diffs:
            return str(len(target))

        bits = 2**len(target) - 1
        for i in range(2**len(target)):
            if all(d & i for d in diffs) and bits_len(target, i) > bits_len(target, bits):
                bits = i

        abbr = []
        pre = 0
        for i in range(len(target)):
            if bits & 1:
                if i - pre > 0:
                    abbr.append(str(i - pre))
                pre = i + 1
                abbr.append(str(target[i]))
            elif i == len(target) - 1:
                abbr.append(str(i - pre + 1))
            bits >>= 1

        return "".join(abbr)
[2]:
s = Solution1()
assert s.minAbbreviation("apple", ["blade"]) == 'a4'
assert s.minAbbreviation("apple", ["plain", "amber", "blade"]) == '1p3'